package com.focus.pay.core.handler;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.focus.pay.core.action.PayNoticeAction;
import com.focus.pay.core.annation.PayNoticeHandler;
import com.focus.pay.core.exception.ExceptionEnum;
import com.focus.pay.core.exception.PayException;
import com.focus.pay.core.utils.AssertUtils;
import com.focus.pay.core.utils.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 赵参谋
 * @version $
 * =========================================================================
 * 变更履历：
 * -------------------------------------------------------------------------
 * 变更编号     变更时间    变更人   变更原因    变更内容
 * -------------------------------------------------------------------------
 * <p>
 * @description：支付回调
 * @date 2022/1/12 17:16
 **/
public class PayNoticeHandlerDistribute {

    private static final Log log = LogFactory.get();

    private static String scanPackage = "com.focus.pay";
    private static String format = "%s#%s#%s#%s";

    public static Map<String, Class> map;

    /**
     * 扫描注解,加载到容器
     */
    static {
        map = new Reflections(scanPackage).getTypesAnnotatedWith(PayNoticeHandler.class).stream()
                .collect(Collectors.toMap(
                        item -> {
                            PayNoticeHandler callbackHandler = item.getAnnotation(PayNoticeHandler.class);
                            String channel = callbackHandler.channel().toString();
                            String channelMethod = callbackHandler.method();
                            String version = callbackHandler.version();
                            String extension = callbackHandler.extension();
                            return String.format(format, channel, channelMethod, version, extension);
                        },
                        item -> item
                ));
    }

    public static <T> T action(PayNoticeAction payNoticeAction) {
        String channel = payNoticeAction.getChannel().toString();
        String channelMethod = payNoticeAction.getMethod();
        String version = Objects.isNull(payNoticeAction.getVersion()) ? StringUtils.EMPTY : payNoticeAction.getVersion();
        String extension = Objects.isNull(payNoticeAction.getExtension()) ? StringUtils.EMPTY : payNoticeAction.getExtension();
        String handlerKey = String.format(format, channel, channelMethod, version, extension);
        try {
            //判断容器是否包含执行类
            AssertUtils.notNull(map.get(handlerKey), () -> new PayException(ExceptionEnum.HANDLE_ERROR));
            //获取执行类
            Class clz = map.get(handlerKey);
            //获取执行方法
            Method method = clz.getMethod(channelMethod, payNoticeAction.getParams().getClass(), payNoticeAction.getConfig().getClass());
            //反射调用
            return (T) method.invoke(clz.newInstance(), payNoticeAction.getParams(), payNoticeAction.getConfig());

        } catch (PayException payException) {
            log.error(payException.getExceptionMsg() + "NoticeHandler:[" + handlerKey + "]", payException);
            return null;
        } catch (NoSuchMethodException exception) {
            log.error("未找到执行方法", exception);
            return null;
        } catch (Exception e) {
            log.error("未知异常", e);
            return null;
        }
    }
}
